home *** CD-ROM | disk | FTP | other *** search
- Using Fifo's:
-
- Fifo's (first-in first-out pipes) are actually very easy to
- use. Here are a couple of things to keep in mind:
-
- (1) The server program (the one that's going to be listening
- for requests from clients) should create the fifo with
- Fcreate(). The file descriptor returned from Fcreate is
- the "server" descriptor; descriptors returned by Fopen will
- be "client" descriptors. Data written to the server descriptor
- can be read by client descriptors, and vice-versa.
- (2) Fifos are by default bidirectional. You can create a single
- directional fifo by creating the fifo "read only"; in this case,
- only the server descriptor can be written to, and only client
- descriptors can be read from.
- (3) Be careful not to mix data up; if two clients are trying to
- read from the same fifo at the same time, they each may read
- data intended for the other. The easiest way to avoid this is
- by having every client lock the fifo before accessing it,
- and unlock the fifo when finished. It's also possible (if you're
- careful) to use the fact that all writes of <1024 bytes are atomic
- (i.e. take place in one "chunk") to avoid interleaving of data;
- but locks are probably safer.
-
- The flags to the Fcreate() system call used to create the fifo can
- be used to control the way the fifo works. For most applications,
- the flags should probably be 0, i.e. the call should look like
- serverfd = Fcreate("U:\\PIPE\\FIFO", 0);
- but for some specialized applications it may be useful to use one
- or more of the following flags (they may be or'd together:
-
- FA_RDONLY: Make the fifo unidirectional; the server fd will be write
- only, and the client fd read only.
- FA_HIDDEN: Make reads from the fifo return "end of file" if no other
- process has the fifo open for writing. This is normally not desired
- for server processes, since the server's read will often occur
- when nobody has the fifo open, and should wait until some client
- does want to use the fifo.
- FA_SYSTEM: Make the fifo a "pseudo-terminal". This type of fifo behaves
- just like a terminal, and most of the terminal control Fcntl calls
- can operate on it. Also, data can be passed through the fifo in long
- words rather than in bytes, if the Fputchar() system call is used.
- This allows the server program to pass the extended BIOS information
- (such as the shift key status and scan code) to be returned by Bconin()
- calls on the client side of the pipe. The 'extra' 3 bytes of the longword
- could also be used for other out of band data as well.
- FA_CHANGED: Make the fifo return from an Fread() call as soon as any data are
- available (just like a terminal). This isn't necessary if the FA_SYSTEM
- bit is set (since pseudo-terminals already act like terminals), but is
- useful for making ordinary fifo's emulate Unix pipe semantics.
-
- Here is a sample pair of applications. The server program ("fortserv.c")
- creates a fifo and listens on it for requests. When it receives a
- request, it writes a cute saying (a "fortune cookie") back to the fifo.
- The client program ("fortune.c") opens the fifo, writes a request,
- reads the response, and prints the result on the terminal. These are
- very simple minded applications, but it should give you an idea of
- the flavour of how to use fifos for interprocess communication.
- -------------------------- fortserv.c -------------------------
- /* fortune server: send cookies to clients */
- /* illustrates server side use of fifos */
-
- /*
- * This program opens a fifo ("U:\PIPE\FORTUNE")
- * and listens to requests on that fifo. When it
- * gets a request (consisting of a single '?'
- * character) it writes back as a reply a 1 byte
- * "length" followed by a randomly selected saying.
- * BUGS:
- * - maximum of 255 characters for a fortune
- * - the fortunes aren't particularly interesting
- */
-
- #ifdef __GNUC__
- #include <minimal.h>
- #endif
- #include <osbind.h>
- #include <mintbind.h>
- #include <string.h>
-
- #define FIFONAME "U:\\PIPE\\FORTUNE"
- #define MAXSIZE 255
-
- /* witty (?) sayings */
-
- char * sayings[] = {
- "Core fault -- program dumped.",
- "Don't worry, be happy!",
- "Help! I'm trapped in a fortune cookie factory!",
- "\"Home is where you wear-a your hat.\"",
- "I want a cookie.",
- "MS-DOS: just say \"no\".",
- "Never play leapfrog with a unicorn.",
- "No matter where you go, there you are.",
- "Sorry, I'm out of short, pithy sayings today.\r\nTry again later.",
- "They say that playing NetHack is like walking into a death trap.",
- "Vision hazy, try again later.",
- "What? You expected something funny?",
- "Why is it that UFO's always seem to visit idiots?",
- "Your puny intellect is no match for our superior weapons.",
- };
- #define NUMSAYINGS (sizeof(sayings) / sizeof(char *))
-
- /* file descriptor for the fortune fifo */
- int fd;
-
-
- /* send a witty saying out through the fifo */
-
- void
- send_saying()
- {
- int i;
- char *s;
- char tmpbuf[MAXSIZE+1];
-
- /* pick a saying at random */
- i = ((unsigned)Random() >> 1) % NUMSAYINGS;
- s = sayings[i];
-
- /* construct the message to send */
- i = (int)strlen(s);
- tmpbuf[0] = i;
- strcpy(tmpbuf+1,s);
-
- /* we really should check for an error */
- (void)Fwrite(fd, (long)i+1, tmpbuf);
- }
-
- /* main function: create the fifo, then sit around
- * listening for requests
- */
-
- int
- main(argc, argv, envp)
- int argc;
- char **argv, **envp;
- {
- char c;
- long r;
-
- fd = Fcreate(FIFONAME, 0);
- if (fd < 0) {
- Cconws("Couldn't create ");
- Cconws(FIFONAME);
- Cconws("!\r\n");
- Pterm(1);
- }
-
- for(;;) {
- r = Fread(fd, 1L, &c);
- if (r != 1) { /* read error?? */
- break;
- }
- if (c == '?') { /* request for saying */
- send_saying();
- }
- /* could have other requests here */
- }
- return 0;
- }
- ------------------------ fortune.c ----------------------
- /* fortune client: get a fortune cookie from
- * the fortune server
- */
-
- /* illustrates client side use of fifos */
-
- #ifdef __GNUC__
- #include <minimal.h>
- #endif
- #include <osbind.h>
- #include <mintbind.h>
-
- #define FIFONAME "U:\\PIPE\\FORTUNE"
- #define BUFSIZ 256
- #define F_SETLKW 7
-
- struct flock {
- short l_type; /* type of lock */
- #define F_RDLCK 0
- #define F_WRLCK 1
- #define F_UNLCK 3
- short l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
- long l_start; /* start of locked region */
- long l_len; /* length of locked region */
- short l_pid; /* pid of locking process
- (F_GETLK only) */
- };
-
- int
- main(argc, argv, envp)
- int argc;
- char **argv, **envp;
- {
- int fd;
- char buf[BUFSIZ];
- unsigned char len;
- struct flock lock;
- long r;
-
- /* open the fifo */
- fd = Fopen(FIFONAME, 2);
- if (fd < 0) {
- Cconws("Couldn't open ");
- Cconws(FIFONAME);
- Cconws("!\r\n");
- Pterm(1);
- }
-
- /* get a lock; this makes sure that two fortune
- * programs don't try to send requests and read
- * replys at the same time
- */
-
- lock.l_type = F_WRLCK;
-
- /* lock the whole file -- only thing that makes sense
- * for a fifo
- */
- lock.l_whence = 0;
- lock.l_start = lock.l_len = 0L;
-
- r = Fcntl(fd, &lock, F_SETLKW);
- if (r != 0) {
- Cconws("Couldn't get a lock!\r\n");
- Pterm(r);
- }
-
- /* write the request */
- Fwrite(fd, 1L, "?");
- /* wait for a reply */
- /* the fortune server writes a 1 byte length, followed by
- * the fortune itself
- */
- r = Fread(fd, 1L, &len);
- if (r != 1L || len != Fread(fd, (long)len, buf)) {
- Cconws("Error reading fortune!\r\n");
- Pterm(1);
- }
- buf[len] = 0;
-
- /* unlock the fifo */
-
- lock.l_type = F_UNLCK;
- (void) Fcntl(fd, &lock, F_SETLKW);
-
- Fclose(fd);
-
- /* now write the fortune to the screen */
- Cconws(buf);
- Cconws("\r\n");
-
- return 0;
- }
-